#include "db_utils.h"
#include "cms_alarm.h"
#include <syslog.h>


#ifdef DBUS_OBJECT_NOTIFY
cms_dbusNotify_t *g_dbusObj_list = NULL;
#endif
pthread_mutex_t dbMtx = PTHREAD_MUTEX_INITIALIZER;
//pthread_cond_t dbCond = PTHREAD_COND_INITIALIZER;
uint32_t saveCnt = 0;

static int cmsDb_msgHandle(cms_dbQueue_t *dbQ, cmsMsg_header_t *msgHeader){
	CMS_LOG(LL_DEBUG, "Entrance.\n");
	cmsMsgCb_t *pCurMsg = dbQ->pMsg, *pReplyMsg = NULL;
	cmsMsg_action_t *pAction = NULL;
	uint32_t actionNum = msgHeader->actionNum;
	cmsBoolean taskNotifyFlag = pCurMsg->header.taskNotify;
	cmsBoolean cwmpNotifyFlag = pCurMsg->header.cwmpNotify;
	int status = -1;
	int ret = -1;
	int flag = 0;
	int replyFlag = 0; /*get action need reply msg*/
	
	CMS_LOG(LL_DEBUG, "before parse, src from %s,  aNum is %d,  moduleid is %d, dtsId %d, taskNotifyFlag %d\n", 
		dbQ->pMsg->header.srcPidname,
		actionNum, pCurMsg->header.srcModuleId, pCurMsg->header.dstModuleId, taskNotifyFlag);
	/*check msg is reqeust or reponse*/
	if(pCurMsg->header.flag & CMS_MSG_REQUEST){
		while(actionNum > 0){
			pAction = cms_parseMsgAction(pCurMsg);
			if(pAction == NULL){
				CMS_LOG(LL_ERROR, "msg action parse fail.\n");
				cms_msgFree(pCurMsg);
				return -1;
			}

			switch(pAction->action->type){
				case CMS_MSG_ACT_SEL:
					ret = cmsDb_selObjByName(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_SELID:
					ret = cmsDb_selObjById(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_SELBYOFFSET:
					ret = cmsDb_selObjByOffset(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_OBJECT_RESTORE:
					ret = cmsDb_objValueRestore(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_ADDOBJBYID:
					ret = cmsDb_addObjByOID(dbQ, pAction, taskNotifyFlag);
					
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_SUCCESS;
						flag |= ((taskNotifyFlag == TRUE ) ? CMS_DB_APPLY : 0);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_FAIL;
					}
					
					break;
				case CMS_MSG_ACT_ADDOBJBYPATH:
					ret = cmsDb_addObjByPath(dbQ, pAction, taskNotifyFlag);
					
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_SUCCESS;
						flag |= ((taskNotifyFlag == TRUE ) ? CMS_DB_APPLY : 0);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_FAIL;
					}

					break;
				case CMS_MSG_ACT_DELOBJBYID:
					ret = cmsDb_delObjByOID(dbQ, pAction, taskNotifyFlag);
					
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_SUCCESS;
						flag |= ((taskNotifyFlag == TRUE ) ? CMS_DB_APPLY : 0);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_FAIL;
					}
					
					break;
				case CMS_MSG_ACT_DELOBJBYPATH:
					ret = cmsDb_delObjByPath(dbQ, pAction, taskNotifyFlag);
					
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_SUCCESS;
						flag |= ((taskNotifyFlag == TRUE ) ? CMS_DB_APPLY : 0);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_FAIL;
					}

					break;
				case CMS_MSG_ACT_GETOBJ:
					ret = cmsDb_getObj(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					flag |= CMS_NO_NEED_REPLY;
					replyFlag = 1;
					break;
				case CMS_MSG_ACT_SETPARA:
					ret = cmsDb_setParameter(dbQ, pAction, taskNotifyFlag, cwmpNotifyFlag);
					
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_SUCCESS;
						flag |= ((taskNotifyFlag == TRUE ) ? CMS_DB_APPLY : 0);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						status = CMS_STATUS_FAIL;
					}
					
					break;
				case CMS_MSG_ACT_GETPARA:
					ret = cmsDb_getParameter(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					replyFlag = 1;
					break;
				case CMS_MSG_ACT_SETATTR:
					ret = cmsDb_setParaAttr(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_GETATTR:
					ret = cmsDb_getParaAttr(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					replyFlag = 1;
					break;
				case CMS_MSG_ACT_SAVE:
					CMS_LOG(LL_PRINT,"cms_db save request from pid:%d",pAction->save->pid);
					flag |= CMS_DB_SAVE;
					
					break;
				case CMS_MSG_ACT_RESTORDEFAULT:
					cms_log_record("****************cms db restoredefault action as below****************");
					cms_log_record("restoreType: ALL 0x0, SHORT 0x1, LONG 0x2; restoreSrc: CLI 0x1, Button 0x2, Web 0x3, tr069 0x4, dbus 0x5, osgi 0x6, omci 0x7, oam 0x8.");
					char cmdStr[256] = {0};
					sprintf(cmdStr, "src process name %s, restoreType %d, restoreSrc %d.", dbQ->pMsg->header.srcPidname,
						cmsRestoreType(pAction->eventContent->typeSizeOfValue), cmsRestoreSource(pAction->eventContent->typeSizeOfValue));
					cms_log_record(cmdStr);
					
					ret = cmsDb_restoreDefault(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
						syslog(LOG_ALERT, "Restore to default configure file failure, Alarm ID: %s", ALARM_FILE_RESTORE_FAIL);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					cms_log_record("****************cms db restoredefault action as above****************");
					break;
				case CMS_MSG_ACT_PRE_DEFAULT:
				case CMS_MSG_ACT_RESTORECONF:
					ret = cmsDb_restoreConf(dbQ, pAction);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					
					break;
				case CMS_MSG_ACT_SET_LOG:
					ret = cmsSetLogLevel(pAction, CMS_DB);
					if(ret == 0){
						SET_ACK(pAction->action->type);
						SET_ACK(dbQ->pMsg->header.flag);
					}else{
						SET_NACK(pAction->action->type);
						SET_NACK(dbQ->pMsg->header.flag);
					}
					status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
					flag |= CMS_NO_NEED_REPLY;
					break;
				default:
					CMS_LOG(LL_ERROR, "not support action type 0x%x.\n", pAction->action->type);
					break;
			}
			
			actionNum--;
		}
		
		cmsDb_dbusNotify(dbQ);

		if(dbQ->pMsg->header.flag & CMS_MSG_NOREPLY)
			flag |= CMS_NO_NEED_REPLY;

		if(flag & CMS_DB_SAVE){
			ret = cmsDb_save(dbQ);
			status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
		}
		
		if(flag & CMS_DB_APPLY){
			ret = cmsDb_handleApply(dbQ, msgHeader);
			status = ((ret == 0) ? CMS_STATUS_SUCCESS : CMS_STATUS_FAIL);
		}

		CMS_LOG(LL_DEBUG, "cms msg handle result is %d, flag %d, status %d\n", ret, flag, status);
		if((flag & CMS_NO_NEED_REPLY) != CMS_NO_NEED_REPLY){
			if(replyFlag== 1){
				pReplyMsg = cms_createReplyMsg(dbQ->pMsg, status);
				if(pReplyMsg != NULL){
					CMS_LOG(LL_DEBUG, "before send, xmltest moduleid is %d\n", dbQ->pMsg->header.srcModuleId);
					if(cms_sendMsg(pReplyMsg, dbQ->pMsg->header.srcModuleId) == -1){
						CMS_LOG(LL_ERROR, "send to src module fail, src module not register to cms_core, src queue id %u(%s [%s]), error code %d(%s).\n",
				 			dbQ->pMsg->header.srcModuleId, dbQ->pMsg->header.srcModuleName, dbQ->pMsg->header.srcPidname, errno, strerror(errno));
						cms_msgAndShmFree(pReplyMsg);
					}else
						cms_msgFree(pReplyMsg);
				}
			}else{
				cmsStatsBuf_t statsBuf;
				statsBuf.mType = dbQ->pMsg->header.msgType;
				statsBuf.statsRet = status;
				statsBuf.timeStamp.tv_sec = dbQ->pMsg->header.timeStamp.tv_sec;
				statsBuf.timeStamp.tv_nsec = dbQ->pMsg->header.timeStamp.tv_nsec;
				 if(msgsnd(dbQ->pMsg->header.srcModuleId, &statsBuf, sizeof(cmsStatsBuf_t)-sizeof(long), IPC_NOWAIT) == -1)
				 	CMS_LOG(LL_ERROR, "send to src module fail, src module not register to cms_core, src queue id %u(%s [%s]), error code %d(%s).\n",
				 		 dbQ->pMsg->header.srcModuleId, dbQ->pMsg->header.srcModuleName , dbQ->pMsg->header.srcPidname, errno, strerror(errno));
			}
	
		}
		cms_msgFree(dbQ->pMsg);
		

	}else{
		CMS_LOG(LL_ERROR, "recv msg type flag 0x%x, error.\n", dbQ->pMsg->header.flag);
		cms_msgFree(dbQ->pMsg);
		return -1;
	}

	CMS_LOG(LL_DEBUG, "Exit.\n");
	return 0;
}

static void cmsDb_initDbQ(cms_dbQueue_t *dbQ){
	dbQ->recordObjFlag = 0;
	dbQ->curObjIA = 0;
	dbQ->curObjOffset = 0;
	dbQ->curObjId = 0;
	dbQ->curObjName = NULL;
	dbQ->objChgList = NULL;
	dbQ->pMsg = NULL;
}

static void *cmsDb_saveHandle(void *arg)
{
	cmsXmlCb_t *xmlShmCb = (cmsXmlCb_t *)arg;
	int saveAction = 0;
	while(1){
		pthread_mutex_lock(&dbMtx);
		if(saveCnt != 0){
			saveAction = 1;
			saveCnt = 0;
		}
		pthread_mutex_unlock(&dbMtx);

		if(saveAction == 1){
			cmsXmlSave(xmlShmCb);
			saveAction = 0;
		}

		usleep(10*1000);
	}
	return (void *)NULL;
}


int main(int argc, char* argv[]){
	cmsMsgCb_t *pRecvMsg = NULL;
	cmsMsg_header_t *pHeader = NULL;
	cms_dbQueue_t *dbQ = NULL;
	pthread_t saveBakThread;
	int ret = -1;

    cmsSetLogLevel(NULL, CMS_DB);

	/*int cms_db module, register to cms_core*/
	ret = cmsDb_init();
	if(ret == -1){
		CMS_LOG(LL_ERROR, "db init fail.\n");
		return -1;
	}

	dbQ = (cms_dbQueue_t *)calloc(1, sizeof(cms_dbQueue_t));
	if(dbQ == NULL){
		cms_unregisterModule(CMS_DB);
		CMS_LOG(LL_ERROR, "dbQ malloc fail.\n");
		return -1;
	}
	
	cmsXmlCb_t *xmlShmCb = XMLSHMINIT();
	if (xmlShmCb == NULL){
		safe_free(dbQ);
		CMS_LOG(LL_ERROR, "xmlShm init error.\r\n");
		return -1;
	}
	dbQ->xmlShmCb = xmlShmCb;

	
	ret = pthread_create(&saveBakThread, NULL, cmsDb_saveHandle, (void *)xmlShmCb);	
	if(ret != 0){
		CMS_LOG(LL_ERROR, "cms db thread create fail.\n");
		goto exit;
	}

	if(nice(-20) == -1){
        CMS_LOG(LL_ERROR, "set nice value failed!");
    }
	while(1){
		pRecvMsg = cms_recvMsg(0,0);

		if(pRecvMsg)
		{
			cmsDb_initDbQ(dbQ);
			dbQ->pMsg = pRecvMsg;
			
			/*parse msg header, and check if NULL*/
			pHeader = cms_parseMsgHeader(pRecvMsg);
			if(pHeader == NULL){
				CMS_LOG(LL_ERROR, "msg header parse fail.\n");
				
				cms_msgFree(pRecvMsg);
	
				continue;
			}

			CMS_LOG(LL_DEBUG, "cmsDB, srcModuleId is %d, %d***********************\n", pHeader->srcModuleId, pRecvMsg->header.srcModuleId);
			/*handle msg received*/
			cmsDb_msgHandle(dbQ, pHeader);
			
		}
	}

exit:
	XMLSHMDEINIT(dbQ->xmlShmCb);
	safe_free(dbQ);
	cms_unregisterModule(CMS_DB);

	pthread_join(saveBakThread, NULL);
	pthread_mutex_destroy(&dbMtx);
//	pthread_cond_destroy(&dbCond);
	CMS_LOG(LL_DEBUG, "db process exit.\n");
	return 0;
}

